package com.cictec.middleware.ribbon.loadbalancer.rule;

import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.cictec.middleware.ribbon.aspect.ThreadContextHolder;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

/**
 * 自定义 gps分析服务负载规则 目前只针对单独分发程序使用，如果是分发服务也是集群，需要重写
 * 
 * @author ql
 *
 */
public class MiddlewareGPSRule extends AbstractLoadBalancerRule {

	/**
	 * 将相同cityCode 相同线路的设备放入同一个middleware-gps服务中处理
	 * 
	 * cityCode
	 * 		devLineId
	 * 			devCode
	 * 
	 * 
	private ConcurrentHashMap determineCurrentMap = new ConcurrentHashMap();
	 */
	
	/**
	 * 将相同cityCode 相同线路的设备放入同一个middleware-gps服务中处理
	 * 
	 * cityCode
	 * 		devLineId
	 * 			devCode
	 * 
	 * 
	 */
	private ConcurrentHashMap<String, Set<String>> determineCurrentMap = new ConcurrentHashMap<String, Set<String>>();
	
	/**
	 * 选择能被2整除的server
	 * 
	 * @param lb
	 * @param key
	 * @return
	 */
	public Server choose(ILoadBalancer lb, Object key) {
		
		String cityCode = ThreadContextHolder.getCityCode();
//		System.out.println("==========>"+cityCode);
//		Thread current = Thread.currentThread();  
//        System.out.println(current.getPriority());  
//        System.out.println(current.getName());  
		if (lb == null) {
			return null;
		}
		Server server = null;

		while (server == null) {
			if (Thread.interrupted()) {
				return null;
			}
			List<Server> upList = lb.getReachableServers();
			List<Server> allList = lb.getAllServers();
//			System.out.println("upList=" + upList);
//			System.out.println("allList=" + allList);
			

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }
            
			
			if(upList.size() > 0){
				// 判定设备是否在维护的map中，没有新增
				for (Server _server : upList) {
					String serverId = _server.getId();
					if(!determineCurrentMap.containsKey(serverId)){
						Set<String> set = ConcurrentHashMap.<String> newKeySet();
						determineCurrentMap.put(serverId, set);
					}
				}
				
				for (Server _server : upList) {
					String serverId = _server.getId();
					if(determineCurrentMap.containsKey(serverId)){
						Set<String> cityCodeSet = determineCurrentMap.get(serverId);
						if(cityCodeSet.contains(cityCode)){
							// 该服务中包含该城市编码中的设备
							if (_server.isAlive()) {
								server = _server;
								break;
							}
						}
					}
				}
				
				// 根据城市编码没有选择到GPS服务
				if(server == null){
					// 根据服务节点，默认向节点城市编码少的服务添加
					int cityCodeSize = 1000;	// 城市编码不会多余1000个
					for (Server _server : upList) {
						int _cityCodeSize = determineCurrentMap.get(_server.getId()).size();
						if(_cityCodeSize < cityCodeSize){
							cityCodeSize = _cityCodeSize;
							server = _server;
						}
					}
					
					if(server != null){
						if(!determineCurrentMap.get(server.getId()).contains(cityCode)){
							determineCurrentMap.get(server.getId()).add(cityCode);
						}
					}
				}
			}
			
			if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }
			
			if (server.isAlive()) {
				
				System.out.println(determineCurrentMap.hashCode() + "\t" + cityCode + "==================>"+server.getHost() + "\t" + server.getHostPort() + "\t" + server.getId());
                return (server);
            }

			// Shouldn't actually happen.. but must be transient or a bug.
			server = null;
			Thread.yield();
		}

		return server;

	}

	@Override
	public Server choose(Object key) {
		// TODO Auto-generated method stub
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub

		System.out.println("==========================>initWithNiwsConfig"+clientConfig);
	}

}
